﻿using System;
using CppUT.Common;
using CppUT.NativeMethods;
using System.Diagnostics;
using System.Messaging;

namespace ManagedApp
{
    internal class StandAloneTestRunner
    {
        internal StandAloneTestRunner(string dllPath)
        {
            _testRunner = CppUnitModel.CreateTestRunner();
            CppUnitModel.LoadTests(_testRunner, dllPath);

            _serverMessageCommunicator = new TestDataCommunicator(Constants.ServerMessagesQueue, CommunicationType.Transmit);
            _clientMessageCommunicator = new TestDataCommunicator(Constants.ClientMessagesQueue, CommunicationType.Receive);
            _testMetaData = new TestMetaData(_testRunner);
        }

        internal void Listen()
        {
            //  Listen to client's messages.
            _clientMessageCommunicator.MessageAvailable += ClientMessageCommunicatorMessageAvailable;
        }

        private void ClientMessageCommunicatorMessageAvailable(System.Messaging.Message message)
        {
            ProcessMessage(message);
        }

        private void ProcessMessage(System.Messaging.Message message)
        {
            Log.MethodEntry();
            Log.Info("Message received: " + message.Label);
            try
            {
                switch (message.Label)
                {
                    case TestMessageValues.GetTestMetaData:
                        {
                            _testMetaData.Refresh();
                            _serverMessageCommunicator.SendMessage(TestMessageValues.TestMetaDataAvailable,
                                                                   _testMetaData.GetTests());
                            break;
                        }
                    case TestMessageValues.RunTest:
                        {
                            message.Formatter = new XmlMessageFormatter(new[] {typeof (string)});
                            var testName = message.Body as string;
                            var testSuccessful = CppUnitModel.RunTest(_testRunner, testName);
                            _serverMessageCommunicator.SendMessage(TestMessageValues.TestResult,
                                                                   new TestResult(testName, testSuccessful));
                            break;
                        }
                    case TestMessageValues.TerminateTestRunner:
                        {
                            _serverMessageCommunicator.Close();
                            _clientMessageCommunicator.Close();
                            break;
                        }
                    default:
                        {
                            throw new ArgumentException("Invalid test message value.");
                        }
                }
            }
            catch(Exception ex)
            {
                ErrorManager.LogException(ex);
                throw;
            }

            Log.MethodExit();
        }

        private TestMetaData _testMetaData;
        private readonly IntPtr _testRunner;
        private TestDataCommunicator _serverMessageCommunicator;
        private TestDataCommunicator _clientMessageCommunicator;
    }
}
